package com.yjzx.util.common.util.collection;


import com.yjzx.util.common.util.BeanUtils.BaseClass;
import com.yjzx.util.common.util.map.NodeMap;

import java.util.*;
import java.util.function.BiFunction;
import java.util.function.Function;
import java.util.function.Predicate;
import java.util.stream.Collectors;
import java.util.stream.Stream;

/**
 * @author yjzx
 * @date 2024/6/13
 * @description CollectorUtil
 */
public class CollectionUtil {
    public static <T> Predicate<T> toTrue() {
        return t -> true;
    }

    public static <K, V> Map<K, V> toMap(List<NodeMap<K, V>> list) {
        return toMap(true, list, toTrue(), NodeMap::getKey, NodeMap::getValue);
    }

    public static <T, K, V> Map<K, V> toMap(Collection<T> collections, Function<T, K> keyMapper, Function<T, V> valueMapper) {
        return toMap(true, collections, toTrue(), keyMapper, valueMapper);
    }

    public static <T, K, V> Map<K, V> toMap(boolean isCover, Collection<T> collections, Function<T, K> keyMapper, Function<T, V> valueMapper) {

        return toMap(isCover, collections, toTrue(), keyMapper, valueMapper);
    }

    /**
     * 因stream流 value无法存在null，重写tomap
     *
     * @param isCover     是否覆盖
     * @param collections 输入的集合
     * @param predicate   筛选条件
     * @param keyMapper   map的key
     * @param valueMapper map的value
     * @param <T>         输入的泛型
     * @param <K>         map key泛型
     * @param <V>         map value泛型
     * @return
     */
    public static <T, K, V> Map<K, V> toMap(boolean isCover, Collection<T> collections, Predicate<T> predicate, Function<T, K> keyMapper, Function<T, ? extends V> valueMapper) {
        return Optional.of(collections).map(
                x -> {
                    int size = collections.size();
                    size = hashMapSize(size);
                    Map<K, V> map = new HashMap<>(size);
                    if (isCover) {
                        for (T collection : collections) {
                            if ( predicate.test(collection)) {
                                coverToMap(keyMapper, valueMapper, map, collection);
                            }
                        }
                    } else {
                        for (T collection : collections) {
                            if (predicate.test(collection)) {
                                notCoverToMap(keyMapper, valueMapper, map, collection);
                            }
                        }
                    }
                    return map;
                }).orElse((Map<K, V>) Collections.EMPTY_MAP);
    }

    private static <T, K, V> void coverToMap(Function<T, K> keyMapper, Function<T, ? extends V> valueMapper, Map<K, V> map, T collection) {
        K apply = keyMapper.apply(collection);
        map.put(apply, valueMapper.apply(collection));
    }

    private static <T, K, V> void notCoverToMap(Function<T, K> keyMapper, Function<T, ? extends V> valueMapper, Map<K, V> map, T collection) {
        K apply = keyMapper.apply(collection);
        map.putIfAbsent(apply, valueMapper.apply(collection));
    }


    public static <T, K, V> Map<K, List<V>> toMapValueList(Collection<T> collections, Function<T, K> keyMapper, Function<T, V> valueMapper) {
        return toMapValueCollection(collections, toTrue(), keyMapper, new BaseClass<List<V>>() {
        }, valueMapper);
    }

    /**
     * list分组
     *
     * @param collections 输入的集合
     * @param predicate   筛选条件
     * @param keyMapper   map的key
     * @param valueMapper map的value
     * @param <T>         输入的泛型
     * @param <K>         map key泛型
     * @param <V>         map value泛型
     * @return
     */
    public static <T, K, V> Map<K, List<V>> toMapValueList(Collection<T> collections, Predicate<T> predicate, Function<T, K> keyMapper, Function<T, V> valueMapper) {
        return toMapValueCollection(collections, predicate, keyMapper, new BaseClass<List<V>>() {
        }, valueMapper);
    }


    public static <T, K, V> Map<K, Set<V>> toMapValueSet(Collection<T> collections, Function<T, K> keyMapper, Function<T, V> valueMapper) {
        return toMapValueCollection(collections, toTrue(), keyMapper, new BaseClass<Set<V>>() {
        }, valueMapper);
    }

    public static <T, K, V> Map<K, Set<V>> toMapValueSet(Collection<T> collections, Predicate<T> predicate, Function<T, K> keyMapper, Function<T, V> valueMapper) {
        return toMapValueCollection(collections, predicate, keyMapper, new BaseClass<Set<V>>() {
        }, valueMapper);
    }

    /**
     * list<T> ->map<k,v>
     * @param collections 输入的集合
     * @param predicate 过滤函数
     * @param keyMapper map的key转换
     * @param valueMapper map的value转换 (t,oldV) -> v
     * @param <T>
     * @param <K>
     * @param <V>
     * @return
     */
    public static <T, K, V> Map<K, V> toMapValue(Collection<T> collections, Predicate<? super T> predicate, Function<? super T, ? extends K> keyMapper, BiFunction<? super T, ? super V, ? extends V> valueMapper) {
        Map<K, V> map = new HashMap<>(16);
        for (T collection : collections) {
            if (predicate.test(collection)) {
                K k = keyMapper.apply(collection);
                V v = valueMapper.apply(collection, map.get(k));
                map.put(k, v);
            }
        }
        return map;
    }
    /**
     * 因stream流 value无法存在null，重写tomap
     *
     * @param collections 输入的集合
     * @param predicate   筛选条件
     * @param keyMapper   map的key
     * @param valueMapper map的value
     * @param <T>         输入的泛型
     * @param <K>         map key泛型
     * @param <V>         map value泛型
     * @return
     */
    public static <T, K, U extends Collection<V>, V> Map<K, U> toMapValueCollection(Collection<T> collections, Predicate<T> predicate, Function<T, K> keyMapper, BaseClass<U> clazz, Function<T, V> valueMapper) {

        return Optional.of(collections).map(
                x -> {
                    Map<K, U> map = new HashMap<>(16);
                    for (T collection : x) {
                        if (predicate.test(collection)) {
                            K k = keyMapper.apply(collection);
                            V v = valueMapper.apply(collection);
                            map.putIfAbsent(k, clazz.newGenericClassInstance().get());
                            map.get(k).add(v);
                        }
                    }
                    return map;
                }).orElse((Map<K, U>) Collections.EMPTY_MAP);

    }

    public static <R, T> List<R> toList(Collection<T> collections, Function<T, R> valueMapper) {
        return toCollection(collections, toTrue(), new BaseClass<List<R>>() {
        }, valueMapper);
    }


    public static <R, T> List<R> toList(Collection<T> collections, Predicate<T> predicate, Function<T, R> valueMapper) {
        return toCollection(collections, predicate, new BaseClass<List<R>>() {
        }, valueMapper);

    }

    public static <R, T> Set<R> toSet(Collection<T> collections, Function<T, R> valueMapper) {
        return toCollection(collections, toTrue(), new BaseClass<Set<R>>() {
        }, valueMapper);
    }

    public static <R, T> Set<R> toSet(Collection<T> collections, Predicate<T> predicate, Function<T, R> valueMapper) {

        return toCollection(collections, predicate, new BaseClass<Set<R>>() {
        }, valueMapper);
    }

    public static <R, T, U extends Collection<R>> U toCollection(Collection<T> collections, Predicate<T> predicate, BaseClass<U> clazz, Function<T, ? extends R> valueMapper) {
        return Optional.of(collections).map(x -> {
            U collection = upSize(clazz.newGenericClassInstance().get(), collections.size());
            for (T v : x) {
                if (predicate.test(v)) {
                    collection.add(valueMapper.apply(v));
                }
            }
            return collection;
        }).orElse(clazz.newGenericClassInstance().get());

    }

    /**
     * list->list<list>
     * @param collections 参数
     * @param predicate 过滤条件
     * @param valueMapper 结果转换
     * @param <R>
     * @param <V>
     * @param <T>
     * @return
     */
    public static <R, V, T extends Collection<V>> List<R> binaryListToList(Collection<T> collections, Predicate<T> predicate, Function<V, ? extends R> valueMapper) {
        return binaryCollectionToCollection(collections, predicate, new BaseClass<List<R>>() {
        }, valueMapper);
    }

    public static <V, T, R extends Collection<V>> List<V> listToBinaryList(Collection<T> collections, Predicate<T> predicate, Function<T, ? extends R> valueMapper) {
        return collectionToBinaryCollection(collections, predicate, new BaseClass<List<V>>() {
        }, valueMapper);

    }

    public static <R, V, T extends Collection<V>, U extends Collection<R>> U binaryCollectionToCollection(Collection<T> collections, Predicate<T> predicate, BaseClass<U> clazz, Function<V, ? extends R> valueMapper) {
        return Optional.of(collections).map(x -> {
            U u = upSize(clazz.newGenericClassInstance().get(), collections.size());
            for (T collection : x) {
                if (predicate.test(collection)) {
                    for (V v : collection) {
                        u.add(valueMapper.apply(v));
                    }
                }
            }
            return u;
        }).orElse(clazz.newGenericClassInstance().get());
    }

    public static <V, T, R extends Collection<V>, U extends Collection<V>> U collectionToBinaryCollection(Collection<T> collections, Predicate<T> predicate, BaseClass<U> clazz, Function<T, ? extends R> valueMapper) {
        return Optional.of(collections).map(x -> {
            U u = upSize(clazz.newGenericClassInstance().get(), collections.size());
            for (T collection : x) {
                if (predicate.test(collection)) {
                    u.addAll(valueMapper.apply(collection));
                }
            }
            return u;
        }).orElse(clazz.newGenericClassInstance().get());
    }


    public static <K, T> List<NodeMap<K, T>> mapToNodeMap(Map<K, T> map) {
        return Optional.of(map).map(x -> x.entrySet().stream().map(NodeMap::of).collect(Collectors.toList())).orElse(Collections.emptyList());
    }

    public static <T extends Collection<V>, K, V> List<NodeMap<V, K>> toReversedNodeMap(Map<K, T> map) {
        return Optional.of(map).map(x -> toReversedNodeMap(mapToNodeMap(map))).orElse(Collections.emptyList());
    }

    public static <T extends Collection<V>, K, V> List<NodeMap<V, K>> toReversedNodeMap(List<NodeMap<K, T>> list) {
        return Optional.of(list).map(x -> binaryListToList(toList(x, toTrue(), node -> {
            K key = node.getKey();
            T value = node.getValue();
            List<NodeMap<V, K>> arrayList = new ArrayList<>();
            for (V v : value) {
                arrayList.add(new NodeMap<>(v, key));
            }
            return arrayList;
        }), toTrue(), Function.identity())).orElse(Collections.emptyList());
    }

    private static <T> T upSize(T t, int size) {
        if (t instanceof ArrayList) {
            ((ArrayList<?>) t).ensureCapacity(size);
        }
        return t;
    }

    public static int hashMapSize(int size) {
        size = (int) (size / 0.75);
        int a = 1;
        while (size > 1) {
            size = size >> 1;
            a++;
        }
        size = 1 << Math.min(a, 8);
        return size;
    }

    /**
     * 获取list 左差集
     *
     * @param list1
     * @param list2
     * @param <T>
     * @return
     */
    public static <T> List<T> leftDifferenceSetList(List<T> list1, List<T> list2) {
        Set<T> tempSet = nullCollectionToEmptySet(list2);
        return nullCollectionToEmptyList(list1).stream().filter(str -> !tempSet.contains(str)).collect(Collectors.toList());
    }

    /**
     * 获取list 右差集
     *
     * @param list1
     * @param list2
     * @param <T>
     * @return
     */
    public static <T> List<T> rightDifferenceSetList(List<T> list1, List<T> list2) {
        Set<T> tempSet = nullCollectionToEmptySet(list1);
        return nullCollectionToEmptyList(list2).stream().filter(str -> !tempSet.contains(str)).collect(Collectors.toList());
    }

    /**
     * 获取list 差集
     *
     * @param list1
     * @param list2
     * @param <T>
     * @return
     */
    public static <T> List<T> differenceSetList(List<T> list1, List<T> list2) {
        Set<T> tempSet1 = nullCollectionToEmptySet(list1);
        Set<T> tempSet2 = nullCollectionToEmptySet(list2);
        return Stream.concat(tempSet1.stream().filter(str -> !tempSet2.contains(str)), tempSet2.stream().filter(str -> !tempSet1.contains(str))).collect(Collectors.toList());
    }

    /**
     * 获取list 并集
     *
     * @param list1
     * @param list2
     * @param <T>
     * @return
     */
    public static <T> List<T> joinList(List<T> list1, List<T> list2) {
        Set<T> tempSet = nullCollectionToEmptySet(list1);
        tempSet.addAll(nullCollectionToEmptyList(list2));
        return new ArrayList<>(tempSet);
    }

    /**
     * 获取list 交集
     *
     * @param list1
     * @param list2
     * @param <T>
     * @return
     */
    public static <T> List<T> intersectionList(List<T> list1, List<T> list2) {
        Set<T> tempSet = nullCollectionToEmptySet(list1);
        return nullCollectionToEmptyList(list2).stream().filter(tempSet::contains).collect(Collectors.toList());
    }

    public static <T> List<T> nullCollectionToEmptyList(Collection<T> collection) {
        return EmptyUtils.isEmpty(collection) ? Collections.emptyList() : collection instanceof List ? (List<T>) collection : new ArrayList<>(collection);
    }

    public static <T> Set<T> nullCollectionToEmptySet(Collection<T> collection) {
        return EmptyUtils.isEmpty(collection) ? Collections.emptySet() : collection instanceof Set ? (Set<T>) collection : new HashSet<>(collection);
    }


}
